When a program violates the semantic constraints of a programming language (e.g., Object-oriented computer programming languages, such as Java™, C++, C#, among others), an error may be signaled (e.g., by a virtual machine or other execution environment) to the program as an exception, which may be defined as an event that occurs during the execution of a program that disrupts the normal flow of instructions. One example of such a violation is an attempt to index outside the bounds of an array. Some programming languages and their implementations react to such errors by peremptorily terminating the program while other programming languages allow an implementation to react in an arbitrary or unpredictable way.
Still, other programming languages (e.g., Java™) specify that an exception will be thrown when one or more semantic constraints are violated and will cause a non-local transfer of control from the point where the exception occurred to a point that can be specified by the programmer. An exception is said to be thrown from the point where it occurred and is said to be caught at the point to which control is transferred. During the process of throwing an exception, the Java™ virtual machine may abruptly complete, one by one, any expressions, statements, method and constructor invocations, initializers, and field initialization expressions that have begun, but have not completed execution in the current thread. This is often referred to as “unwinding the stack.” This process may continue until a handler is found that indicates that it handles that particular exception by naming the class of the exception or a superclass of the class of the exception. If no such handler is found, then the exception may be handled by one of a hierarchy of uncaught exception handlers.
In some instances, a second exception occurs while the first exception is still in the midst of being handled as opposed to exceptions merely being sequential (e.g., the first exception is raised and handled, then the second exception is raised and handled). As an example using try-catch-finally and try-finally statements, if one exception occurs within one code block (e.g., a try block) and then a subsequent exception occurs in another code block (e.g., a finally block), the first occurring exception is discarded (e.g., neither stored, nor propagated) and the subsequent exception is propagated. Further elaborating on the example, if a finally block is executed because of abrupt completion of a try block and the finally block itself completes abruptly, then the reason for the abrupt completion of the try block may be discarded and the new reason for the abrupt completion may be propagated. In such instances, information regarding the first error is lost, obscuring the root cause, making the problem harder to diagnose and debug, resulting in systems that are less reliable and robust.